using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;

namespace aleph.framework.SqlInstall
{
	/// <summary>
	/// SQL DataBase installer
	/// </summary>
	/// <remarks>
	/// Developer: Stefan Prodan
	/// Blog: http://www.alephdev.blogspot.com
	/// </remarks>
	[RunInstaller(true)]
	public class ScriptInstall : Installer
	{
		//default value, it will be overwrite by the installer
		string conStr="packet size=4096;integrated security=SSPI;"+
					"data source=\"(local)\";persist security info=False;"+
					"initial catalog=master";
		private Container components=null;
		
		public ScriptInstall()
		{
			// This call is required by the Designer.
			InitializeComponent();
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{

		}
		#endregion

		private static string GetScript(string name)
		{
			Assembly asm = Assembly.GetExecutingAssembly();
			Stream str = asm.GetManifestResourceStream(asm.GetName().Name+ "." + name);
			StreamReader reader = new StreamReader(str);
			return reader.ReadToEnd();
		}
		private static string GetLogin(string databaseServer,string database)
		{
			return "server=" + databaseServer + ";database="+database+";integrated security=SSPI;";
		}

		private static void ExecuteSql(SqlConnection sqlCon)
		{
			string[] SqlLine;
			Regex regex = new Regex("^GO",RegexOptions.IgnoreCase | RegexOptions.Multiline);
			
			string txtSQL = GetScript("install.txt");
			SqlLine = regex.Split(txtSQL);

			SqlCommand cmd = sqlCon.CreateCommand();
			cmd.Connection = sqlCon;

			foreach(string line in SqlLine)
			{
				if(line.Length>0)
				{
					cmd.CommandText = line;
					cmd.CommandType = CommandType.Text;
					try
					{
						cmd.ExecuteNonQuery();
					}
					catch(SqlException)
					{
						//rollback
						ExecuteDrop(sqlCon);
						break;
					}
				}
			}
		}
		private static void ExecuteDrop(SqlConnection sqlCon)
		{	
			if(sqlCon.State!=ConnectionState.Closed)sqlCon.Close();
			sqlCon.Open();
			SqlCommand cmd = sqlCon.CreateCommand();
			cmd.Connection = sqlCon;
			cmd.CommandText = GetScript("uninstall.txt");
			cmd.CommandType = CommandType.Text;
			cmd.ExecuteNonQuery();
			sqlCon.Close();
		}

		public override void Install(IDictionary stateSaver)
		{
			base.Install (stateSaver);

            //if (Context.Parameters["databaseServer"].Length > 0 &&
            //    Context.Parameters["userName"].Length > 0 &&
            //    Context.Parameters["userPass"].Length > 0)
            //{
            //    conStr = GetLogin(
            //        Context.Parameters["databaseServer"],
            //        Context.Parameters["userName"],
            //        Context.Parameters["userPass"],
            //        "master");

            //}
            conStr = GetLogin(@".\SQLEXPRESS", "master");
		    RijndaelCryptography rijndael = new RijndaelCryptography();
		    rijndael.GenKey();
		    rijndael.Encrypt(conStr);
		    //save information in the state-saver IDictionary
		    //to be used in the Uninstall method
		    stateSaver.Add("key",rijndael.Key);
		    stateSaver.Add("IV",rijndael.IV);
		    stateSaver.Add("conStr",rijndael.Encrypted);
			
			SqlConnection sqlCon = new SqlConnection(conStr);

			sqlCon.Open();
			ExecuteSql(sqlCon);
			if(sqlCon.State!=ConnectionState.Closed)sqlCon.Close();
		}

		public override void Uninstall(IDictionary savedState)
		{
			base.Uninstall (savedState);

			if(savedState.Contains("conStr"))
			{
				RijndaelCryptography rijndael = new RijndaelCryptography();
				rijndael.Key = (byte[])savedState["key"];
				rijndael.IV = (byte[])savedState["IV"];
				conStr = rijndael.Decrypt((byte[])savedState["conStr"]);			
			}

			SqlConnection sqlCon = new SqlConnection(conStr);
	
			ExecuteDrop(sqlCon);
		}

        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);

            if (savedState.Contains("conStr"))
            {
                RijndaelCryptography rijndael = new RijndaelCryptography();
                rijndael.Key = (byte[])savedState["key"];
                rijndael.IV = (byte[])savedState["IV"];
                conStr = rijndael.Decrypt((byte[])savedState["conStr"]);
            }

            SqlConnection sqlCon = new SqlConnection(conStr);

            ExecuteDrop(sqlCon);
        }

 

	}
}
